#!/usr/bin/env python

'''cloud api for paas'''
import xml2dict
import os
import sys
import subprocess
import pp
import re
import xmlrpclib
import hashlib
from IaaSSql import *

'''environment variable'''
HOME_DIR=os.getenv('HOME')
ONE_XMLRPC=os.getenv('ONE_XMLRPC')

'''variable'''
CONF_DIR = "/tmp/cloud"
SRC_FILE = "/srv/cloud/images/base.one"
DB_HOST = "localhost"
DB_USER = "cloud"
DB_PASSWD = "cloudpass"
DB = "crane"

if not ONE_XMLRPC:
    ONE_XMLRPC="http://localhost:2633/RPC2"

'''initialize the configure file of vms'''
def init_conf(f_conf):
    if "name" not in f_conf:
        f_conf["name"] = f_conf["user"]
    if "memory" not in f_conf:
        f_conf["memory"] = "512"
    if "vcpu" not in f_conf:
        f_conf["vcpu"] = 1
    if "cpu" not in f_conf:
        f_conf["cpu"] = f_conf["vcpu"]
    if "HOME" not in f_conf:
        f_conf["HOME"] = HOME_DIR
    if "count" not in f_conf:
        f_conf["count"] = 1
    if "type" not in f_conf:
        f_conf["type"] = 1

'''get the auth of the user'''
def get_auth(u_name):
    if len(u_name) == 2:
        return str(u_name[0])+":"+hashlib.sha1(str(u_name[1])).hexdigest()
    else:
        return str(u_name)+":"+hashlib.sha1(str(u_name)+"pass").hexdigest()

def get_uid(user):
    conn = connectDB(DB_HOST, DB_USER, DB_PASSWD, DB)
    cursor = cursorDB(conn)
    row = selectone(cursor, "select oid from user_pool where user_name='" + str(user) + "'")
    closeDB(cursor)
    closeDB(conn)
    return int(row[0])

'''get the img file type
ret 0 para-vm
    1 full-vm
    2 not exists'''
def get_vm_type(img_file):
    exist = os.path.exists(img_file)
    if not exist:
        return 2
    f = subprocess.Popen(("/usr/bin/file", img_file), stdout = subprocess.PIPE).stdout
    FILE_TYPE = f.readline()
    f.close()
    TYPE = re.search("ext3", FILE_TYPE)
    if TYPE:
        return 0
    else:
        return 1

'''create a vm'''
def vm_sub(auth, CON_F):
    ONE_XMLRPC = "http://localhost:2633/RPC2"
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.allocate(auth, CON_F)
    if result[0]:
        return result[1]
    else:
        return -1

'''create vms one by one'''
def vms_submit(user, CON_F, num):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    ids = []
    index = 0
    while index < num:
        result = server.one.vm.allocate(auth, CON_F)
        if result[0]:
            index += 1
            ids.append(result[1])   
    return ids

'''create vms in parallel with the file'''
def p_vms_submit(user, CON_F, num):
    auth = get_auth(user)
    ppservers = ()
    job_server = pp.Server(num, ppservers=ppservers)
    ids = []
    jobs = []
    index = 0
    while index < num:
        jobs.append(job_server.submit(vm_sub, (auth, CON_F), (), ("re", "xmlrpclib", "subprocess")))
        index += 1
    for job in jobs:
        id=job()
        if id is not -1:
            ids.append(id)   
    return ids

'''get a ip from a id'''
def get_ip(auth, id):
    ONE_XMLRPC = "http://localhost:2633/RPC2"
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.info(auth, int(id))
    if result[0]:
        is_ip = re.search('<IP>([\.0-9]*)</IP>', result[1])
        if is_ip:
            return [str(id), is_ip.group(1)]
        else:
            return -1

'''get ips from ids one by one'''
def get_ip_list(user, id_list):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    ip_list = []
    index = 0
    while index < len(id_list):
        result = server.one.vm.info(auth, int(id_list[index]))
        if result[0]:
            is_ip = re.search('<IP><!\[CDATA\[([\.0-9]*)\]\]></IP>', result[1])
            if is_ip:
                ip_list.append([str(id_list[index]),is_ip.group(1)])
                index += 1
    return ip_list

'''parallel get ips from ids'''
def p_get_ip_list(user, id_list):
    auth =  get_auth(user)
    ppservers = ()
    job_server = pp.Server(len(id_list), ppservers=ppservers)
    ip_list = []
    jobs = []
    index = 0
    while index < len(id_list):
        jobs.append(job_server.submit(get_ip, (auth, id_list[index]), (), ("re", "xmlrpclib", "subprocess")))
        index += 1
    for job in jobs:
        ip = job()
        ip_list.append(ip)
    return ip_list

'''delete a vm of the user with the id'''
def vm_delete(user, vm_id):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.action(auth, "finalize", int(vm_id))
    return result

'''delete a group of vms from vm_id_start to vm_id_end'''
def del_vms(vm_id_start, vm_id_end, user):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    for each in range(int(vm_id_start), int(vm_id_end)+1):
        server.one.vm.action(auth, "finalize", each)


'''creat vms with a configure file'''
def vm_create(HVM):
    init_conf(HVM)
    f=os.popen('date +%s')
    DATE=f.readline().strip()
    f.close()
    CONF_FILE=CONF_DIR+os.sep+HVM["user"]+"_"+DATE+".one"
    subprocess.call(("/bin/cp",SRC_FILE,CONF_FILE))
    fp=open(CONF_FILE,"a")
    clone = "yes"
    if int(HVM["type"]) is 0:
        clone = "no"
    for each in ["name","cpu","memory","vcpu","HOME"]:
        fp.write(each+"="+str(HVM[each])+os.linesep)
    fp.write(r'''GRAPHICS=[type ="vnc",listen="0.0.0.0"]'''+os.linesep)
    fp.write(r'''RAW =[type="xen",data="builder='hvm'"]'''+os.linesep)
    fp.write(r'''RAW =[type="xen",data="device_model='/usr/lib64/xen/bin/qemu-dm'"]'''+os.linesep)
    fp.write(r'''OS  =[kernel="/usr/lib/xen/boot/hvmloader" ]'''+os.linesep)
    vm_type = get_vm_type(HVM["img"])
    if vm_type == 1:
        '''full-vm'''
        fp.write(r'''DISK=[source="'''+HVM["img"]+r'''", target = "hda", clone = "'''+clone+'''"]'''+os.linesep)
    elif vm_type == 2:
        img_source = get_image_source(HVM["img"])
        fp.write(r'''DISK=[source="'''+img_source+r'''", target = "hda", clone = "'''+clone+'''"]'''+os.linesep)
        '''para-vm'''
    elif vm_type == 0:
        pass
    fp.close()
    fp = open(CONF_FILE, "r")
    fp_content = fp.read().strip()
    fp.close()
    id_list = vms_submit(HVM["user"], fp_content, int(HVM["count"]))
    subprocess.call(("/bin/rm","-f", CONF_FILE))
    return get_ip_list(HVM["user"], id_list)

def vm_xml_dict(xml):
    state = ["INIT", "PENDING", "HOLD", "RUNNING", "STOPPED", "SUSPENDED", "DONE", "FAIL"]
    ret = {}
    ret["guid"] = xml.ID
    ret["owner"] = xml.USERNAME
    ret["hostMachine"] = xml.HISTORY.HOSTNAME
    ret["name"] = xml.NAME
    ret["cpu"] = "1"
    ret["stat"] = state[int(xml.STATE)]
    ret["memory"] = xml.MEMORY
    return ret
    

'''delete a vm of the user with the id'''
def get_vm_info(user, vm_id):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.info(auth, int(vm_id))
    if result[0]:
        xml = xml2dict.XML2Dict()
        ret = xml.fromstring(result[1])
        result[1] = {}
        result[1]["id"] = vm_id
        result[1]["ip"] = ret.VM.TEMPLATE.NIC.IP
        result[1]["host"] = ret.VM.HISTORY.HOSTNAME
    return result
    
'''get the information of the vms'''
def get_vmpool_info(user):
    flag = -1
    if user[0] == "crane":
        flag = -2
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vmpool.info(auth, flag)
    if result[0]:
        xml = xml2dict.XML2Dict()
        ret = xml.fromstring(result[1])
        result[1] = []
        print ret.VM_POOL
        if "VM" in ret.VM_POOL:
            for each in ret.VM_POOL.VM:
                result[1].append(vm_xml_dict(each))
    return result

'''control the vm'''
def vm_action(user, action, vm_id):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.action(auth, action, int(vm_id))
    return result

def vm_migrate(user, vm_id, host_id, livemigration):
    auth = get_auth(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.vm.migrate(auth, int(vm_id), int(host_id), livemigration)
    return result

'''add a host to the list of the host'''
def host_create(host, vmm):
    auth = get_auth("crane")
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.host.allocate(auth, host, "im_"+vmm, "vmm_"+vmm, "tm_nfs", True)
    return result

def get_vms_host(host_name):
    vms_list = [];
    ret = get_vmpool_info(["crane", "cranepass"])
    if ret[0]:
        for each in ret[1]:
            if each["hostMachine"] == host_name:
                vms_list.append(each["guid"])   
    return vms_list

def host_xml_dict(xml):
    ret = {}
    ret["guid"] = xml.ID
    ret["name"] = xml.NAME
    ret["totalMemory"] = xml.HOST_SHARE.MAX_MEM
    ret["freeMemory"] = xml.HOST_SHARE.FREE_MEM
    ret["virtualMachines"] = get_vms_host(xml.NAME) 
    ret["totalCpu"] = xml.HOST_SHARE.MAX_CPU
    ret["usedCpu"] = xml.HOST_SHARE.USED_CPU
    return ret
    

'''get host information'''
def get_host_info(host_id):
    auth = get_auth("crane")
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.host.info(auth, int(host_id))
    if result[0]:
        xml = xml2dict.XML2Dict()
        ret = xml.fromstring(result[1])
        result[1] = host_xml_dict(ret.HOST)
    return result

'''get hostpool information'''
def get_hostpool_info():
    auth = get_auth("crane")
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.hostpool.info(auth)
    if result[0]:
        xml = xml2dict.XML2Dict()
        ret = xml.fromstring(result[1])
        result[1] = []
        if "HOST" in ret.HOST_POOL:
            for each in ret.HOST_POOL.HOST:
                result[1].append(host_xml_dict(each))
    return result

'''delete a host from the host pool'''
def host_delete(host_id):
    auth = get_auth("crane")
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.host.delete(auth, int(host_id))
    return result

def user_create(user, passwd):
    password = hashlib.sha1(str(passwd)).hexdigest()
    auth = get_auth("crane")
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.user.allocate(auth, str(user), str(password))
    return result
    
def user_delete(user, passwd="pass"):
    auth = get_auth("crane")
    user_id = get_uid(user)
    server = xmlrpclib.ServerProxy(ONE_XMLRPC) 
    result = server.one.user.delete(auth, int(user_id))
    return result

def get_image_info(user):
    conn = connectDB(DB_HOST, DB_USER, DB_PASSWD, DB)
    cursor = cursorDB(conn)
    rows = select(cursor, "select distinct image_pool.oid, name, source, running_vms from image_pool,user_pool where public=1 or (user_name='bxie' and uid=user_pool.oid)")
    closeDB(cursor)
    closeDB(conn)
    return rows
    
def get_image_source(name):
    conn = connectDB(DB_HOST, DB_USER, DB_PASSWD, DB)
    cursor = cursorDB(conn)
    row = selectone(cursor, "select source from image_pool where name='" + str(name) + "'")
    closeDB(cursor)
    closeDB(conn)
    return row[0]

'''test'''
if __name__ == "__main__":
    #HVM={ 'user':'test','memory':'512','vcpu':'5','img':'/srv/cloud/images/full/rhel5_x86_64_base.img','count':1 }
    HVM={ 'user':'test','memory':'512','vcpu':'5','img':'rhel5','count':1 }
    #date1=subprocess.call(("/bin/date","+%T"))
    ret=vm_create(HVM)
    #date1=subprocess.call(("/bin/date","+%T"))
    #ret = user_create("test","testpass")
    #ret = user_delete("test")
    #ret = get_auth(["crane","cranepass"])
    #ret = get_uid("bxie")
    #ret = get_image_source("RHEL5")
    #ret = get_image_info("bxie")
    #ret = get_hostpool_info()
    #print ret
    #ret = get_host_info(0)
    #print ret
    #del_vms(388, 390,"crane")
    #ret = get_vm_info(["crane","cranepass"],171)
    #xml = xml2dict.XML2Dict()
    #ret = xml.fromstring(ret[1])
    #ret = get_vmpool_info([u"crane",u"cranepass"])
    print ret
    #ret = vm_delete(["crane","cranepass"],118)
    #ret = host_create("blade05","xen")
    #rint ret
    pass
